import My3D.Point3D;
/* the 3D Matrix's structure
* [	[xx,yx,zx]
* 	[xy,yy,zy]
* 	[xz,yz,zz] ]
* */

dynamic class My3D.Matrix3D {
	//---------------------------------------------  matrix
	public var xx:Number;
	public var yx:Number;
	public var zx:Number;
	
	public var xy:Number;
	public var yy:Number;
	public var zy:Number;
	
	public var xz:Number;
	public var yz:Number;
	public var zz:Number;
	
	public static var say:Function;
	
	public function Matrix3D(obj:Array){
		this.matrixArray=new Array();
		if(obj==undefined){
			yx = zx = xy = zy = xz = yz = 0;
			xx = yy = zz = 1;
		}else {
			xx = obj[0][0];
			yx = obj[0][1];
			zx = obj[0][2];
			
			xy = obj[1][0];
			yy = obj[1][1];
			zy = obj[1][2];
			
			xz = obj[2][0];
			yz = obj[2][1];
			zz = obj[2][2];
		}
	}
	
	///Matrix 
	public function X(m2:Matrix3D):Matrix3D{
		if(m2==undefined)
		{
			return this;
		}
		return Matrix3D.Matrix3X3(this,m2);
	}
	
	public static function multiplyVector( m:Matrix3D, v:Point3D ):Void
	{
		var vx:Number, vy:Number, vz:Number;
		v.x = (vx=v.x) * m.xx + (vy=v.y) * m.yx + (vz=v.z) * m.zx;
		v.y = vx * m.xy + vy * m.yy + vz * m.zy;
		v.z = vx * m.xz + vy * m.yz + vz * m.zz;
	}
	public static function MatrixXStringCase(m1:Array, m2:Array):Array {
		if (m1 == undefined) {
			return m1;
		} else if (m2 == undefined) {
			return m2;
		}
		
		var rma:Array = new Array();
		for (var i = 0; i<m1.length; i++) {
			rma[i] = new Array();
			for (var ii = 0; ii<m2[0].length; ii++) {
				//var sum:Number = 0;
				var sum:String="";
				for (var iii = 0; iii<m1[0].length; iii++) {
					//sum += m1[i][iii]*m2[iii][ii];
					sum+="+"+m1[i][iii]+"*"+m2[iii][ii];
				}
				sum="("+sum.substring(1)+")";
				rma[i].push(sum);
			}
		}
		return rma;
	}
	public static function Matrix3X3(m1:Matrix3D, m2:Matrix3D):Matrix3D {
		return new Matrix3D([
		[m1.xx * m2.xx + m1.yx * m2.xy + m1.zx * m2.xz, m1.xx * m2.yx + m1.yx * m2.yy + m1.zx * m2.yz, m1.xx * m2.zx + m1.yx * m2.zy + m1.zx * m2.zz],
		[m1.xy * m2.xx + m1.yy * m2.xy + m1.zy * m2.xz, m1.xy * m2.yx + m1.yy * m2.yy + m1.zy * m2.yz, m1.xy * m2.zx + m1.yy * m2.zy + m1.zy * m2.zz],
		[m1.xz * m2.xx + m1.yz * m2.xy + m1.zz * m2.xz, m1.xz * m2.yx + m1.yz * m2.yy + m1.zz * m2.yz, m1.xz * m2.zx + m1.yz * m2.zy + m1.zz * m2.zz]
		]);
	}
	///Matrix return the X-Axes Rotation transform Matrix3D
	public static function getXRotation(O:Number):Matrix3D{
		return new Matrix3D([
							[1, 0, 0],
							[0, Math.cos(O), Math.sin(O)],
							[0, -Math.sin(O), Math.cos(O)]
							]);
	}
	///Matrix return the Y-Axes Rotation transform Matrix3D
	public static function getYRotation(O:Number):Matrix3D{
		return new Matrix3D([
							[Math.cos(O), 0, -Math.sin(O)],
							[0, 1, 0],
							[Math.sin(O), 0, Math.cos(O)]
							]);
	}
	///Matrix return the Z-Axes Rotation transform Matrix3D
	public static function getZRotation(O:Number):Matrix3D{
		return new Matrix3D([
							[Math.cos(O), Math.sin(O), 0],
							[ -Math.sin(O), Math.cos(O), 0],
							[0, 0, 1]
							]);
	}
	///Matrix return the 3-Axes Rotation transform Matrix
	public static function getFreeAxisRotation(x:Number,y:Number,z:Number,O:Number):Matrix3D{
		if(x==0 && y==0){
			return Matrix3D.getZRotation(O);
		}else if(x==0 && z==0){
			return Matrix3D.getYRotation(O);
		}else if(y==0 && z==0){
			return Matrix3D.getXRotation(O);
		}
		var a1:Number=Math.PI/2;
		var a2:Number=0;
		var y2:Number=Math.pow(y*y+z*z,0.5);
		if(z!=0){
			a1=Math.atan2(y,z);
			a2=-Math.atan2(x,y2);
		}else{
			a2=-Math.atan2(x,y2);
		}
		
		
		//trace(a1+" ||| "+a2);
		var m:Matrix3D = Matrix3D.getXRotation(a1);
		m=m.X(Matrix3D.getYRotation(a2));
		m=m.X(Matrix3D.getZRotation(O));
		m=m.X(Matrix3D.getYRotation(-a2));
		m=m.X(Matrix3D.getXRotation(-a1));
		return m;
	}
	///Matrix return scalment transform
	public static function getScal(x:Number,y:Number,z:Number):Matrix3D{
		return new Matrix3D([[x, 0, 0], [0, y, 0], [0, 0, z]]);
	}
	
	
	public function toString():String{
		var str:String="";
		str += xx + ",\t" + yx + ",\t" + zx + "\r";
		str += xy + ",\t" + yy + ",\t" + zy + "\r";
		str += xz + ",\t" + yz + ",\t" + zz + "\r";
		return str;
	}
	
	private function Say(o:Object){
		var msg:String="Matrix err: "+o.toString();
		if(Matrix3D.say!=undefined){
			Matrix3D.say(msg);
		}else{
			trace(msg);
		}
	}
}